package com.rzjm.api.util;

/**
 * @创建者：zhouwei
 * @创建时间：2022/5/9
 * @描述：
 */
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 使用最小二乘法实现线性回归预测
 *
 * @author daijiyong
 */
public class LinearRegression {
    /**
     * 截距
     */
//    private double intercept = 0.0;
    /**
     * 求斜率的上下两个分式的值
     */
//    private double slopeUp = 0.0, slopeDown = 0.0;

//    public LinearRegression() { }

    /**
     * 根据训练集数据进行训练预测
     * 并计算斜率和截距
     */
    public static Map<String,Object> initData(Map<Double, Double> initData) {
        double averageX = 0.0, averageY = 0.0;
        double slopeUp = 0.0, slopeDown = 0.0;
        Map<String,Object> map = new HashMap<>();
        map.put("code",0);
        if (initData.size() > 0) {
            //数据个数
            int number = 0;
            //x值、y值总和
            double sumX = 0;
            double sumY = 0;
            slopeUp = 0;
            slopeDown = 0;
            for (Double x : initData.keySet()) {
                if (x == null || initData.get(x) == null) {
                    continue;
                }
                number++;
                sumX = DoubleUtils.add(sumX, x);
                sumY = DoubleUtils.add(sumY, initData.get(x));
            }
            //求x，y平均值
            averageX = DoubleUtils.div(sumX, (double) number);
            averageY = DoubleUtils.div(sumY, (double) number);
            for (Double x : initData.keySet()) {
                if (x == null || initData.get(x) == null) {
                    continue;
                }
                slopeUp = DoubleUtils.add(slopeUp, DoubleUtils.mul(DoubleUtils.sub(x, averageX), DoubleUtils.sub(initData.get(x), averageY)));
                slopeDown = DoubleUtils.add(slopeDown, DoubleUtils.mul(DoubleUtils.sub(x, averageX), DoubleUtils.sub(x, averageX)));
            }
            map.putAll(initSlopeIntercept(averageX,averageY,slopeUp, slopeDown));
        }
        return map;
    }
    /**
     * 计算斜率和截距
     */
    private static Map<String,Object> initSlopeIntercept(double averageX, double averageY,double slopeUp,  double slopeDown) {
        double slope = 0d;
        double intercept = 0d;
        Map<String,Object> map = new HashMap<>();
        if (slopeUp != 0 && slopeDown != 0) {
            slope = slopeUp / slopeDown;
        }
//        System.out.println("斜率: " + slope);
        intercept = averageY - averageX * slope;
//        System.out.println("截距: " + intercept);
        map.put("code",1);
        map.put("slope",slope);
        map.put("intercept",intercept);
        return map;
    }

    /**
     *  获取 涓流数据的斜率
     * @param powerList
     * @return
     */
    public static Map<String, Object> getPowerSlope(List<Double> powerList){
//        System.out.println("参与计算的数据个数：" + powerList.size());
//        Map<>
        double slope = 100d;
//		LinearRegression linearRegression1 = new LinearRegression();
        int i = 0;
        Map<Double, Double> initData = new HashMap<>();
        for (Double power : powerList){
            initData.put(Double.parseDouble((i+ 1) + ""), power);
            i++;
        }

//        System.out.println("斜率: " + slope);
//        System.out.println("截距: " + intercept);
        Map<String, Object> map = LinearRegression.initData(initData);
        int code = map.containsKey("code") ? Integer.parseInt(map.get("code").toString()) : 0;
        if(code == 1){
            slope = map.containsKey("slope") ? Double.parseDouble(map.get("slope").toString()) : 100d;
//            System.out.println("带符号的 斜率：" + slope);
            slope = Math.abs(MathUtil.getDoubleUpFour(slope));
//            System.out.println("绝对值 斜率：" + slope);
        }
        return map;
    }
    /**
     * 根据x值预测y值
     *
     * @param x x值
     * @return y值
     */
//    public Double getY(Double x) {
//        double slope = 0d;
//        return DoubleUtils.add(intercept, DoubleUtils.mul(slope, x));
//    }
    /**
     * 根据y值预测x值
     *
     * @param y y值
     * @return x值
     */
//    public Double getX(Double y) {
//        double slope = 0d;
//        return DoubleUtils.div(DoubleUtils.sub(y, intercept), slope);
//    }

    public static void main(String[] args) {
        LinearRegression linearRegression = new LinearRegression();


        List<Double> heights = new ArrayList<>();
        heights.add(1.27d);
        heights.add(1.30d);
//        heights.add(1.27d);
//        heights.add(1.21d);
//        heights.add(1.18d);
//        heights.add(1.28d);
//        heights.add(1.26d);
//        heights.add(1.23d);
//        heights.add(1.22d);
//        heights.add(1.20d);
//        heights.add(1.21d);
//        heights.add(1.17d);
//        heights.add(1.16d);
//        heights.add(1.12d);
//        heights.add(1.07d);
//        heights.add(1.05d);
//        heights.add(1.04d);
//        heights.add(1.00d);
//        heights.add(0.99d);

        Map<String, Object> map = getPowerSlope(heights);
        System.out.println("map" + map.toString());


        double[] data = {
                265.9,269,270.4,270,272.2,272.1,272.5,266.9,271.4,268.8,263.2,268,266.3,267.4,267.7,266.6,271.8,
                270.7,270,273.3,270.4,269.5,270.8,272.7,273.7,274.5,269.8,272.8,271.8,275.3,273.6,271.4,271.1,272.2,
                276.2,266.7,273.2,271.1,271.1,272.2,272.1,274,268,268.5,274,270.8,268.4,272.9,268,273,270,268.5,273.2,
                274.4,271.4,268,272.5,271.9,275.5,272.3,271.8,270.8,271.8,269.3,271.7,266.9,267.7,266.1,272.1,273.3,
                277.3,277.3,275.2,275.8,273.9,276.2,274.8,273.7,274,276.9,276.9,277.2,273.5,273.1,274.3,278,272.8,275.8,
                276.1,280,276.5,278.3,277.7,280.6,281.1,280.4,277.7,275.9,279.5,277.6,276.5,283.8,282.4,283.4,284.4,282.1,
                285.8,284.3,277.7,284.3,279.5,282.8,286.5,280.9,285.9,283.5,283.9,283.2,284,280.6,288.2,285.8,271.9,261.9,
                248.4,234.3,224.7,228.8,215.5,206.6,196.6,189.9,187.1,170.9,167.2,165.2,158.3,151.2,147.3,142,137.8,131.2,126.4,
                122,115.6,112.4,108.2,104.5,102.3,98.1,94.7,92.7,89.5,86.8,84.1,82.5,78.3,76.9,74.6,72.5,70.3,66.9,66.4,63,63.6,
                61.8,60.3,59,55.7,55,53.7,52.4,51.7,50.4,48.2,47.2,46,46,44.8,44,43,41.8,39.7,39.6,5.6,
                9,5.6,11.2,7.8,10.1,5.6,12.4,6.8,5.6,10.1,7.9,5.6,6.7,7.9,10.1,10.1,11.2,10.2,10.1,11.3,
                10.2,6.7,13.5,9.1,10.2,9,10.2,12.4,10.2,13.6,10.1,11.3,13.5,9
        };

//        for (int i=0;i<data.length ;i++){
//            linearRegression.getInitData().put(Double.parseDouble((i+ 1) + ""), data[i]);
//        }

//        linearRegression.initData();

        System.out.println("===================");

        LinearRegression linearRegression1 = new LinearRegression();

        double[] data1 = {
//                5.6, 9,5.6,11.2,7.8,
                10.2,9,10.2,12.4,10.2,13.6,10.1,11.3,13.5,9,12.4,13.5,9,10.1,10.1,9.1,9,9,6.8,11.3,10.1,10.2,9,7.9,10.2,14.7,9,10.2,10.1,12.4
//                ,12.4
        };

//        for (int i=0;i<data1.length ;i++){
//            linearRegression1.getInitData().put(Double.parseDouble((i+ 1) + ""), data1[i]);
//        }
//        linearRegression1.initData();

//训练集数据
//        linearRegression.getInitData().put(1D, 8D);
//        linearRegression.getInitData().put(1.5D, 9.5D);
//        linearRegression.getInitData().put(2D, 11D);
//        linearRegression.getInitData().put(2.5D, 10D);
//        linearRegression.getInitData().put(3D, 14D);
//根据训练集数据进行线性函数预测
//        linearRegression.initData();


//        System.out.println("intercept: " + intercept);


//        /*
//         * 给定x值，预测y值
//         */
//        System.out.println(linearRegression.getY(130D));
//        /*
//         * 给定y值，预测x值
//         */
//        System.out.println(linearRegression.getX(9.5D));
    }
}
